import urllib
import sys
from xml.dom.minidom import parse
import xml
from copy import copy
from exceptions import FlickrException

class FlickrAPI:
    api_key = None
    namespace = 'flickr'
    base_url = 'http://api.flickr.com/services/rest/'
    secret = None
    token = None
    frob = None
    
    def __init__(self, api_key, user_id, secret=None, frob=None):
        self.__dict__['api_key'] = api_key
        self.__dict__['user_id'] = user_id
        
        self.__dict__['secret'] = secret
        
        if frob is not None:
            self.__dict__['frob'] = frob
            self.__dict__['token'] = self.get_token()
    
    def __getattr__(self, name):
        print "getting %s" % name
        
        if name[0] == '_':
            raise AttributeError
        
        from copy import copy
        f = copy(self)
        f.namespace += '.' + name
        
        return f
    
    def __call__(self, **options):
        return FlickrMethod(self, self.namespace).execute(**options)
    
    def __str__(self):
        return '<FlickrAPI instance for ' + self.api_key + ' user ' + self.user_id + '>'
    
    def get_frob(self):
        r = FlickrMethod(self, 'flickr.auth.getFrob').execute()
        frob = r.getElementsByTagName('frob').item(0).firstChild.nodeValue
        
        return frob
    
    def get_token(self):
        r = FlickrMethod(self, 'flickr.auth.getToken').execute(send_user_id=False, frob=self.frob)
        token = r.getElementsByTagName('token').item(0).firstChild.nodeValue
        print token
        return token

class FlickrMethod:
    name = None
    api = None
    response = None
    request = None
    
    def __init__(self, api, name):
        self.name = name
        self.api = api
    
    def __repr__(self):
        return 'FlickrAPIMethod %s' % self.name
    
    def execute(self, send_user_id=True, **options):
        self.request = RESTRequest(self.api.base_url)
        
        self.request.set('method', self.name)
        self.request.set('api_key', self.api.api_key)
        
        if send_user_id:
            self.request.set('user_id', self.api.user_id)
        
        for key, opt in options.iteritems():
            self.request.set(key, opt)
        
        if self.api.token is not None:
            self.request.set('auth_token', self.api.token)
        else:
            print "token: %s" % self.api.token
        
        if self.api.secret is not None:
            self.sign()
        
        self.response = self.request.process_request()
        
        return self.process_response()
    
    def sign(self):
        # Ordering the dictionary
        attrs = self.request.query
        sig = self.api.secret
        for k in sorted(attrs.keys()):
            sig += k + str(attrs[k])
        
        import md5
        
        md5_hash = md5.new()
        md5_hash.update(sig)
        self.request.set('api_sig', md5_hash.hexdigest())
    
    def process_response(self):
        if self.response.firstChild.getAttribute('stat') != u"ok":
            self.handle_error()
            
        return self.response
    
    def handle_error(self):
        error = self.response.firstChild.getElementsByTagName('err').item(0)
        
        code = int(error.getAttribute('code'))
        msg = error.getAttribute('msg')
        
        from exceptions import exceptions_list, FlickrException
        
        if code in exceptions_list.keys():
            raise exceptions_list[code](code, '%s for url %s' % (msg, self.request.url))
        else:
            raise FlickrException(code, msg)
    
    def __str__(self):
        return 'FlickrAPI method for %s with api key %s' % (self.name, self.api.api_key)

class RESTRequest:
    """
    Processes a simple REST request
    """
    
    query = dict()
    base_url = ''
    url = ''
    
    def __init__(self, base_url):
        self.query = dict()
        self.base_url = base_url
    
    def set(self, attr, value):
        print "Setting %s to %s" % (attr, value)
        self.query[attr] = value
    
    def get(self, attr):
        return self.query[attr]
    
    def process_request(self):
        self.url = '%s?%s' % (self.base_url, urllib.urlencode(self.query))
        
        print self.url, "\n"
        
        u = urllib.urlopen(self.url)
        resp = ""
        try:
            resp = parse(u)
        finally:
            u.close()
        
        return resp